/*
Copyright 2019 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package sqlparser

/*
This is the Vitess AST. This file should only contain pure struct declarations,
or methods used to mark a struct as implementing an interface. All other methods
related to these structs live in ast_funcs.go
*/

// SQLNode defines the interface for all nodes
// generated by the parser.
type SQLNode interface {
	Format(buf *TrackedBuffer)
	formatFast(buf *TrackedBuffer)
}

// Statements
type (
	// Statement represents a statement.
	Statement interface {
		iStatement()
		SQLNode
	}

	// SelectStatement any SELECT statement.
	SelectStatement interface {
		Statement
		iSelectStatement()
		iInsertRows()
		AddOrder(*Order)
		SetOrderBy(OrderBy)
		SetLimit(*Limit)
		SetLock(lock Lock)
		SetInto(into *SelectInto)
		SetWith(with *With)
		MakeDistinct()
		GetColumnCount() int
		SetComments(comments Comments)
		GetComments() Comments
	}

	// DDLStatement represents any DDL Statement
	DDLStatement interface {
		iDDLStatement()
		IsFullyParsed() bool
		IsTemporary() bool
		GetTable() TableName
		GetAction() DDLAction
		GetOptLike() *OptLike
		GetIfExists() bool
		GetIfNotExists() bool
		GetTableSpec() *TableSpec
		GetFromTables() TableNames
		GetToTables() TableNames
		AffectedTables() TableNames
		SetTable(qualifier string, name string)
		SetFromTables(tables TableNames)
		SetComments(comments Comments)
		GetComments() Comments
		SetFullyParsed(fullyParsed bool)
		Statement
	}

	// DBDDLStatement represents any DBDDL Statement
	DBDDLStatement interface {
		iDBDDLStatement()
		IsFullyParsed() bool
		GetDatabaseName() string
		SetFullyParsed(bool)
		Statement
	}

	// AlterOption is an interface that represents the various options in ALTER TABLE statements
	AlterOption interface {
		iAlterOption()
		SQLNode
	}

	// Explain is an interface that represents the Explain statements
	Explain interface {
		Statement
		iExplain()
	}

	// AddConstraintDefinition represents a ADD CONSTRAINT alter option
	AddConstraintDefinition struct {
		ConstraintDefinition *ConstraintDefinition
	}

	// AddIndexDefinition represents a ADD INDEX alter option
	AddIndexDefinition struct {
		IndexDefinition *IndexDefinition
	}

	// AddColumns represents a ADD COLUMN alter option
	AddColumns struct {
		Columns []*ColumnDefinition
		First   bool
		After   *ColName
	}

	// AlgorithmValue is the algorithm specified in the alter table command
	AlgorithmValue string

	// AlterColumn is used to add or drop defaults to columns in alter table command
	AlterColumn struct {
		Column      *ColName
		DropDefault bool
		DefaultVal  Expr
	}

	// With contains the lists of common table expression and specifies if it is recursive or not
	With struct {
		ctes      []*CommonTableExpr
		Recursive bool
	}

	// CommonTableExpr is the structure for supporting common table expressions
	CommonTableExpr struct {
		TableID  TableIdent
		Columns  Columns
		Subquery *Subquery
	}
	// ChangeColumn is used to change the column definition, can also rename the column in alter table command
	ChangeColumn struct {
		OldColumn        *ColName
		NewColDefinition *ColumnDefinition
		First            bool
		After            *ColName
	}

	// ModifyColumn is used to change the column definition in alter table command
	ModifyColumn struct {
		NewColDefinition *ColumnDefinition
		First            bool
		After            *ColName
	}

	// AlterCharset is used to set the default or change the character set and collation in alter table command
	AlterCharset struct {
		CharacterSet string
		Collate      string
	}

	// KeyState is used to disable or enable the keys in an alter table statement
	KeyState struct {
		Enable bool
	}

	// TablespaceOperation is used to discard or import the tablespace in an alter table statement
	TablespaceOperation struct {
		Import bool
	}

	// DropColumn is used to drop a column in an alter table statement
	DropColumn struct {
		Name *ColName
	}

	// DropKeyType is an enum that represents the type of key being dropped in an alter table statement
	DropKeyType int8

	// DropKey is used to drop a key in an alter table statement
	DropKey struct {
		Type DropKeyType
		Name ColIdent
	}

	// Force is used to specify force alter option in an alter table statement
	Force struct{}

	// LockOptionType is an enum for LockOption.Type
	LockOptionType int8

	// LockOption is used to specify the type of lock to use in an alter table statement
	LockOption struct {
		Type LockOptionType
	}

	// OrderByOption clause is used to specify the order by in an alter table statement
	OrderByOption struct {
		Cols Columns
	}

	// RenameTableName clause is used to rename the table in an alter table statement
	RenameTableName struct {
		Table TableName
	}

	// RenameIndex clause is used to rename indexes in an alter table statement
	RenameIndex struct {
		OldName ColIdent
		NewName ColIdent
	}

	// Validation clause is used to specify whether to use validation or not
	Validation struct {
		With bool
	}

	// Select represents a SELECT statement.
	Select struct {
		Cache            *bool // a reference here so it can be nil
		Distinct         bool
		StraightJoinHint bool
		SQLCalcFoundRows bool
		// The From field must be the first AST element of this struct so the rewriter sees it first
		From        []TableExpr
		Comments    Comments
		SelectExprs SelectExprs
		Where       *Where
		With        *With
		GroupBy     GroupBy
		Having      *Where
		OrderBy     OrderBy
		Limit       *Limit
		Lock        Lock
		Into        *SelectInto
	}

	// SelectInto is a struct that represent the INTO part of a select query
	SelectInto struct {
		Type         SelectIntoType
		FileName     string
		Charset      string
		FormatOption string
		ExportOption string
		Manifest     string
		Overwrite    string
	}

	// SelectIntoType is an enum for SelectInto.Type
	SelectIntoType int8

	// Lock is an enum for the type of lock in the statement
	Lock int8

	// Union represents a UNION statement.
	Union struct {
		Left     SelectStatement
		Right    SelectStatement
		Distinct bool
		OrderBy  OrderBy
		With     *With
		Limit    *Limit
		Lock     Lock
		Into     *SelectInto
	}

	// VStream represents a VSTREAM statement.
	VStream struct {
		Comments   Comments
		SelectExpr SelectExpr
		Table      TableName
		Where      *Where
		Limit      *Limit
	}

	// Stream represents a SELECT statement.
	Stream struct {
		Comments   Comments
		SelectExpr SelectExpr
		Table      TableName
	}

	// Insert represents an INSERT or REPLACE statement.
	// Per the MySQL docs, http://dev.mysql.com/doc/refman/5.7/en/replace.html
	// Replace is the counterpart to `INSERT IGNORE`, and works exactly like a
	// normal INSERT except if the row exists. In that case it first deletes
	// the row and re-inserts with new values. For that reason we keep it as an Insert struct.
	// Replaces are currently disallowed in sharded schemas because
	// of the implications the deletion part may have on vindexes.
	// If you add fields here, consider adding them to calls to validateUnshardedRoute.
	Insert struct {
		Action     InsertAction
		Comments   Comments
		Ignore     Ignore
		Table      TableName
		Partitions Partitions
		Columns    Columns
		Rows       InsertRows
		OnDup      OnDup
	}

	// Ignore represents whether ignore was specified or not
	Ignore bool

	// InsertAction is the action for insert.
	InsertAction int8

	// Update represents an UPDATE statement.
	// If you add fields here, consider adding them to calls to validateUnshardedRoute.
	Update struct {
		With       *With
		Comments   Comments
		Ignore     Ignore
		TableExprs TableExprs
		Exprs      UpdateExprs
		Where      *Where
		OrderBy    OrderBy
		Limit      *Limit
	}

	// Delete represents a DELETE statement.
	// If you add fields here, consider adding them to calls to validateUnshardedRoute.
	Delete struct {
		With       *With
		Ignore     Ignore
		Comments   Comments
		Targets    TableNames
		TableExprs TableExprs
		Partitions Partitions
		Where      *Where
		OrderBy    OrderBy
		Limit      *Limit
	}

	// Set represents a SET statement.
	Set struct {
		Comments Comments
		Exprs    SetExprs
	}

	// SetTransaction represents a SET TRANSACTION statement.
	SetTransaction struct {
		SQLNode
		Comments        Comments
		Scope           Scope
		Characteristics []Characteristic
	}

	// Scope is an enum for scope of query
	Scope int8

	// Characteristic is a transaction related change
	Characteristic interface {
		SQLNode
		iChar()
	}

	// IsolationLevel is an enum for isolation levels
	IsolationLevel int8

	// AccessMode is enum for the mode - ReadOnly or ReadWrite
	AccessMode int8

	// DropDatabase represents a DROP database statement.
	DropDatabase struct {
		Comments Comments
		DBName   TableIdent
		IfExists bool
	}

	// CollateAndCharsetType is an enum for CollateAndCharset.Type
	CollateAndCharsetType int8

	// CollateAndCharset is a struct that stores Collation or Character Set value
	CollateAndCharset struct {
		Type      CollateAndCharsetType
		IsDefault bool
		Value     string
	}

	// CreateDatabase represents a CREATE database statement.
	CreateDatabase struct {
		Comments      Comments
		DBName        TableIdent
		IfNotExists   bool
		CreateOptions []CollateAndCharset
		FullyParsed   bool
	}

	// AlterDatabase represents a ALTER database statement.
	AlterDatabase struct {
		DBName              TableIdent
		UpdateDataDirectory bool
		AlterOptions        []CollateAndCharset
		FullyParsed         bool
	}

	// Flush represents a FLUSH statement.
	Flush struct {
		IsLocal      bool
		FlushOptions []string
		TableNames   TableNames
		WithLock     bool
		ForExport    bool
	}

	// RenameTablePair represents the name of the original table and what it is going to be set in a RENAME TABLE statement.
	RenameTablePair struct {
		FromTable TableName
		ToTable   TableName
	}

	// RenameTable represents a RENAME TABLE statement.
	RenameTable struct {
		TablePairs []*RenameTablePair
	}

	// TruncateTable represents a TRUNCATE TABLE statement.
	TruncateTable struct {
		Table TableName
	}

	// AlterVschema represents a ALTER VSCHEMA statement.
	AlterVschema struct {
		Action DDLAction
		Table  TableName

		// VindexSpec is set for CreateVindexDDLAction, DropVindexDDLAction, AddColVindexDDLAction, DropColVindexDDLAction.
		VindexSpec *VindexSpec

		// VindexCols is set for AddColVindexDDLAction.
		VindexCols []ColIdent

		// AutoIncSpec is set for AddAutoIncDDLAction.
		AutoIncSpec *AutoIncSpec
	}

	// ShowMigrationLogs represents a SHOW VITESS_MIGRATION '<uuid>' LOGS statement
	ShowMigrationLogs struct {
		UUID     string
		Comments Comments
	}

	// RevertMigration represents a REVERT VITESS_MIGRATION statement
	RevertMigration struct {
		UUID     string
		Comments Comments
	}

	// AlterMigrationType represents the type of operation in an ALTER VITESS_MIGRATION statement
	AlterMigrationType int8

	// AlterMigration represents a ALTER VITESS_MIGRATION statement
	AlterMigration struct {
		Type AlterMigrationType
		UUID string
	}

	// AlterTable represents a ALTER TABLE statement.
	AlterTable struct {
		Table         TableName
		AlterOptions  []AlterOption
		PartitionSpec *PartitionSpec
		Comments      Comments
		FullyParsed   bool
	}

	// DropTable represents a DROP TABLE statement.
	DropTable struct {
		Temp       bool
		FromTables TableNames
		// The following fields are set if a DDL was fully analyzed.
		IfExists bool
		Comments Comments
	}

	// DropView represents a DROP VIEW statement.
	DropView struct {
		FromTables TableNames
		IfExists   bool
	}

	// CreateTable represents a CREATE TABLE statement.
	CreateTable struct {
		Temp        bool
		Table       TableName
		IfNotExists bool
		TableSpec   *TableSpec
		OptLike     *OptLike
		Comments    Comments
		FullyParsed bool
	}

	// CreateView represents a CREATE VIEW query
	CreateView struct {
		ViewName    TableName
		Algorithm   string
		Definer     string
		Security    string
		Columns     Columns
		Select      SelectStatement
		CheckOption string
		IsReplace   bool
	}

	// AlterView represents a ALTER VIEW query
	AlterView struct {
		ViewName    TableName
		Algorithm   string
		Definer     string
		Security    string
		Columns     Columns
		Select      SelectStatement
		CheckOption string
	}

	// DDLAction is an enum for DDL.Action
	DDLAction int8

	// Load represents a LOAD statement
	Load struct {
	}

	// Show represents a show statement.
	Show struct {
		Internal ShowInternal
	}

	// Use represents a use statement.
	Use struct {
		DBName TableIdent
	}

	// Begin represents a Begin statement.
	Begin struct{}

	// Commit represents a Commit statement.
	Commit struct{}

	// Rollback represents a Rollback statement.
	Rollback struct{}

	// SRollback represents a rollback to savepoint statement.
	SRollback struct {
		Name ColIdent
	}

	// Savepoint represents a savepoint statement.
	Savepoint struct {
		Name ColIdent
	}

	// Release represents a release savepoint statement.
	Release struct {
		Name ColIdent
	}

	// CallProc represents a CALL statement
	CallProc struct {
		Name   TableName
		Params Exprs
	}

	// LockType is an enum for Lock Types
	LockType int8

	// TableAndLockType contains table and lock association
	TableAndLockType struct {
		Table TableExpr
		Lock  LockType
	}

	// TableAndLockTypes is a slice of TableAndLockType
	TableAndLockTypes []*TableAndLockType

	// LockTables represents the lock statement
	LockTables struct {
		Tables TableAndLockTypes
	}

	// UnlockTables represents the unlock statement
	UnlockTables struct{}

	// ExplainType is an enum for ExplainStmt.Type
	ExplainType int8

	// ExplainStmt represents an Explain statement
	ExplainStmt struct {
		Type      ExplainType
		Statement Statement
	}

	// ExplainTab represents the Explain table
	ExplainTab struct {
		Table TableName
		Wild  string
	}
	// IntervalTypes is an enum to get types of intervals
	IntervalTypes int8

	// OtherRead represents a DESCRIBE, or EXPLAIN statement.
	// It should be used only as an indicator. It does not contain
	// the full AST for the statement.
	OtherRead struct{}

	// OtherAdmin represents a misc statement that relies on ADMIN privileges,
	// such as REPAIR, OPTIMIZE, or TRUNCATE statement.
	// It should be used only as an indicator. It does not contain
	// the full AST for the statement.
	OtherAdmin struct{}
)

func (*Union) iStatement()             {}
func (*Select) iStatement()            {}
func (*Stream) iStatement()            {}
func (*VStream) iStatement()           {}
func (*Insert) iStatement()            {}
func (*Update) iStatement()            {}
func (*Delete) iStatement()            {}
func (*Set) iStatement()               {}
func (*SetTransaction) iStatement()    {}
func (*DropDatabase) iStatement()      {}
func (*Flush) iStatement()             {}
func (*Show) iStatement()              {}
func (*Use) iStatement()               {}
func (*Begin) iStatement()             {}
func (*Commit) iStatement()            {}
func (*Rollback) iStatement()          {}
func (*SRollback) iStatement()         {}
func (*Savepoint) iStatement()         {}
func (*Release) iStatement()           {}
func (*OtherRead) iStatement()         {}
func (*OtherAdmin) iStatement()        {}
func (*Select) iSelectStatement()      {}
func (*Union) iSelectStatement()       {}
func (*Load) iStatement()              {}
func (*CreateDatabase) iStatement()    {}
func (*AlterDatabase) iStatement()     {}
func (*CreateTable) iStatement()       {}
func (*CreateView) iStatement()        {}
func (*AlterView) iStatement()         {}
func (*LockTables) iStatement()        {}
func (*UnlockTables) iStatement()      {}
func (*AlterTable) iStatement()        {}
func (*AlterVschema) iStatement()      {}
func (*AlterMigration) iStatement()    {}
func (*RevertMigration) iStatement()   {}
func (*ShowMigrationLogs) iStatement() {}
func (*DropTable) iStatement()         {}
func (*DropView) iStatement()          {}
func (*TruncateTable) iStatement()     {}
func (*RenameTable) iStatement()       {}
func (*CallProc) iStatement()          {}
func (*ExplainStmt) iStatement()       {}
func (*ExplainTab) iStatement()        {}

func (*CreateView) iDDLStatement()    {}
func (*AlterView) iDDLStatement()     {}
func (*CreateTable) iDDLStatement()   {}
func (*DropTable) iDDLStatement()     {}
func (*DropView) iDDLStatement()      {}
func (*AlterTable) iDDLStatement()    {}
func (*TruncateTable) iDDLStatement() {}
func (*RenameTable) iDDLStatement()   {}

func (*AddConstraintDefinition) iAlterOption() {}
func (*AddIndexDefinition) iAlterOption()      {}
func (*AddColumns) iAlterOption()              {}
func (AlgorithmValue) iAlterOption()           {}
func (*AlterColumn) iAlterOption()             {}
func (*ChangeColumn) iAlterOption()            {}
func (*ModifyColumn) iAlterOption()            {}
func (*AlterCharset) iAlterOption()            {}
func (*KeyState) iAlterOption()                {}
func (*TablespaceOperation) iAlterOption()     {}
func (*DropColumn) iAlterOption()              {}
func (*DropKey) iAlterOption()                 {}
func (*Force) iAlterOption()                   {}
func (*LockOption) iAlterOption()              {}
func (*OrderByOption) iAlterOption()           {}
func (*RenameTableName) iAlterOption()         {}
func (*RenameIndex) iAlterOption()             {}
func (*Validation) iAlterOption()              {}
func (TableOptions) iAlterOption()             {}

func (*ExplainStmt) iExplain() {}
func (*ExplainTab) iExplain()  {}

// IsFullyParsed implements the DDLStatement interface
func (*TruncateTable) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (*TruncateTable) SetFullyParsed(bool) {}

// IsFullyParsed implements the DDLStatement interface
func (*RenameTable) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (node *RenameTable) SetFullyParsed(fullyParsed bool) {}

// IsFullyParsed implements the DDLStatement interface
func (node *CreateTable) IsFullyParsed() bool {
	return node.FullyParsed
}

// SetFullyParsed implements the DDLStatement interface
func (node *CreateTable) SetFullyParsed(fullyParsed bool) {
	node.FullyParsed = fullyParsed
}

// IsFullyParsed implements the DDLStatement interface
func (node *AlterTable) IsFullyParsed() bool {
	return node.FullyParsed
}

// SetFullyParsed implements the DDLStatement interface
func (node *AlterTable) SetFullyParsed(fullyParsed bool) {
	node.FullyParsed = fullyParsed
}

// IsFullyParsed implements the DDLStatement interface
func (node *CreateView) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (node *CreateView) SetFullyParsed(fullyParsed bool) {}

// IsFullyParsed implements the DDLStatement interface
func (node *DropView) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (node *DropView) SetFullyParsed(fullyParsed bool) {}

// IsFullyParsed implements the DDLStatement interface
func (node *DropTable) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (node *DropTable) SetFullyParsed(fullyParsed bool) {}

// IsFullyParsed implements the DDLStatement interface
func (node *AlterView) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (node *AlterView) SetFullyParsed(fullyParsed bool) {}

// IsTemporary implements the DDLStatement interface
func (*TruncateTable) IsTemporary() bool {
	return false
}

// IsTemporary implements the DDLStatement interface
func (*RenameTable) IsTemporary() bool {
	return false
}

// IsTemporary implements the DDLStatement interface
func (node *CreateTable) IsTemporary() bool {
	return node.Temp
}

// IsTemporary implements the DDLStatement interface
func (node *AlterTable) IsTemporary() bool {
	return false
}

// IsTemporary implements the DDLStatement interface
func (node *CreateView) IsTemporary() bool {
	return false
}

// IsTemporary implements the DDLStatement interface
func (node *DropView) IsTemporary() bool {
	return false
}

// IsTemporary implements the DDLStatement interface
func (node *DropTable) IsTemporary() bool {
	return node.Temp
}

// IsTemporary implements the DDLStatement interface
func (node *AlterView) IsTemporary() bool {
	return false
}

// GetTable implements the DDLStatement interface
func (node *TruncateTable) GetTable() TableName {
	return node.Table
}

// GetTable implements the DDLStatement interface
func (node *CreateTable) GetTable() TableName {
	return node.Table
}

// GetTable implements the DDLStatement interface
func (node *AlterTable) GetTable() TableName {
	return node.Table
}

// GetTable implements the DDLStatement interface
func (node *CreateView) GetTable() TableName {
	return node.ViewName
}

// GetTable implements the DDLStatement interface
func (node *AlterView) GetTable() TableName {
	return node.ViewName
}

// GetTable implements the DDLStatement interface
func (node *DropView) GetTable() TableName {
	return TableName{}
}

// GetTable implements the DDLStatement interface
func (node *DropTable) GetTable() TableName {
	return TableName{}
}

// GetTable implements the DDLStatement interface
func (node *RenameTable) GetTable() TableName {
	return TableName{}
}

// GetAction implements the DDLStatement interface
func (node *TruncateTable) GetAction() DDLAction {
	return TruncateDDLAction
}

// GetAction implements the DDLStatement interface
func (node *AlterTable) GetAction() DDLAction {
	return AlterDDLAction
}

// GetAction implements the DDLStatement interface
func (node *CreateTable) GetAction() DDLAction {
	return CreateDDLAction
}

// GetAction implements the DDLStatement interface
func (node *CreateView) GetAction() DDLAction {
	return CreateDDLAction
}

// GetAction implements the DDLStatement interface
func (node *AlterView) GetAction() DDLAction {
	return AlterDDLAction
}

// GetAction implements the DDLStatement interface
func (node *RenameTable) GetAction() DDLAction {
	return RenameDDLAction
}

// GetAction implements the DDLStatement interface
func (node *DropTable) GetAction() DDLAction {
	return DropDDLAction
}

// GetAction implements the DDLStatement interface
func (node *DropView) GetAction() DDLAction {
	return DropDDLAction
}

// GetOptLike implements the DDLStatement interface
func (node *CreateTable) GetOptLike() *OptLike {
	return node.OptLike
}

// GetOptLike implements the DDLStatement interface
func (node *TruncateTable) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *RenameTable) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *AlterTable) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *CreateView) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *AlterView) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *DropTable) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *DropView) GetOptLike() *OptLike {
	return nil
}

// GetIfExists implements the DDLStatement interface
func (node *RenameTable) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *CreateTable) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *TruncateTable) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *AlterTable) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *CreateView) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *AlterView) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *DropTable) GetIfExists() bool {
	return node.IfExists
}

// GetIfExists implements the DDLStatement interface
func (node *DropView) GetIfExists() bool {
	return node.IfExists
}

// GetIfNotExists implements the DDLStatement interface
func (node *RenameTable) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *CreateTable) GetIfNotExists() bool {
	return node.IfNotExists
}

// GetIfNotExists implements the DDLStatement interface
func (node *TruncateTable) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *AlterTable) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *CreateView) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *AlterView) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *DropTable) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *DropView) GetIfNotExists() bool {
	return false
}

// GetTableSpec implements the DDLStatement interface
func (node *CreateTable) GetTableSpec() *TableSpec {
	return node.TableSpec
}

// GetTableSpec implements the DDLStatement interface
func (node *RenameTable) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *TruncateTable) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *AlterTable) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *CreateView) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *AlterView) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *DropTable) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *DropView) GetTableSpec() *TableSpec {
	return nil
}

// GetFromTables implements the DDLStatement interface
func (node *RenameTable) GetFromTables() TableNames {
	var fromTables TableNames
	for _, pair := range node.TablePairs {
		fromTables = append(fromTables, pair.FromTable)
	}
	return fromTables
}

// GetFromTables implements the DDLStatement interface
func (node *TruncateTable) GetFromTables() TableNames {
	return nil
}

// GetFromTables implements the DDLStatement interface
func (node *AlterTable) GetFromTables() TableNames {
	return nil
}

// GetFromTables implements the DDLStatement interface
func (node *CreateTable) GetFromTables() TableNames {
	return nil
}

// GetFromTables implements the DDLStatement interface
func (node *CreateView) GetFromTables() TableNames {
	return nil
}

// GetFromTables implements the DDLStatement interface
func (node *DropTable) GetFromTables() TableNames {
	return node.FromTables
}

// GetFromTables implements the DDLStatement interface
func (node *DropView) GetFromTables() TableNames {
	return node.FromTables
}

// GetFromTables implements the DDLStatement interface
func (node *AlterView) GetFromTables() TableNames {
	return nil
}

// SetFromTables implements DDLStatement.
func (node *RenameTable) SetFromTables(tables TableNames) {
	if len(node.TablePairs) != len(tables) {
		return
	}
	for i := range node.TablePairs {
		node.TablePairs[i].FromTable = tables[i]
	}
}

// SetFromTables implements DDLStatement.
func (node *TruncateTable) SetFromTables(tables TableNames) {
	// irrelevant
}

// SetFromTables implements DDLStatement.
func (node *AlterTable) SetFromTables(tables TableNames) {
	// irrelevant
}

// SetFromTables implements DDLStatement.
func (node *CreateTable) SetFromTables(tables TableNames) {
	// irrelevant
}

// SetFromTables implements DDLStatement.
func (node *CreateView) SetFromTables(tables TableNames) {
	// irrelevant
}

// SetFromTables implements DDLStatement.
func (node *DropTable) SetFromTables(tables TableNames) {
	node.FromTables = tables
}

// SetFromTables implements DDLStatement.
func (node *DropView) SetFromTables(tables TableNames) {
	node.FromTables = tables
}

// SetFromTables implements DDLStatement.
func (node *AlterView) SetFromTables(tables TableNames) {
	// irrelevant
}

// SetComments implements DDLStatement.
func (node *RenameTable) SetComments(comments Comments) {
	// irrelevant
}

// SetComments implements DDLStatement.
func (node *TruncateTable) SetComments(comments Comments) {
	// irrelevant
}

// SetComments implements DDLStatement.
func (node *AlterTable) SetComments(comments Comments) {
	node.Comments = comments
}

// SetComments implements DDLStatement.
func (node *CreateTable) SetComments(comments Comments) {
	node.Comments = comments
}

// SetComments implements DDLStatement.
func (node *CreateView) SetComments(comments Comments) {
	// irrelevant
}

// SetComments implements DDLStatement.
func (node *DropTable) SetComments(comments Comments) {
	node.Comments = comments
}

// SetComments implements DDLStatement.
func (node *DropView) SetComments(comments Comments) {
	// irrelevant
}

// SetComments implements DDLStatement.
func (node *AlterView) SetComments(comments Comments) {
	// irrelevant
}

// SetComments for RevertMigration, does not implement DDLStatement
func (node *RevertMigration) SetComments(comments Comments) {
	node.Comments = comments
}

// GetComments implements DDLStatement.
func (node *RenameTable) GetComments() Comments {
	// irrelevant
	return nil
}

// GetComments implements DDLStatement.
func (node *TruncateTable) GetComments() Comments {
	// irrelevant
	return nil
}

// GetComments implements DDLStatement.
func (node *AlterTable) GetComments() Comments {
	return node.Comments
}

// GetComments implements DDLStatement.
func (node *CreateTable) GetComments() Comments {
	return node.Comments
}

// GetComments implements DDLStatement.
func (node *CreateView) GetComments() Comments {
	// irrelevant
	return nil
}

// GetComments implements DDLStatement.
func (node *DropTable) GetComments() Comments {
	return node.Comments
}

// GetComments implements DDLStatement.
func (node *DropView) GetComments() Comments {
	// irrelevant
	return nil
}

// GetComments implements DDLStatement.
func (node *AlterView) GetComments() Comments {
	// irrelevant
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *RenameTable) GetToTables() TableNames {
	var toTables TableNames
	for _, pair := range node.TablePairs {
		toTables = append(toTables, pair.ToTable)
	}
	return toTables
}

// GetToTables implements the DDLStatement interface
func (node *TruncateTable) GetToTables() TableNames {
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *AlterTable) GetToTables() TableNames {
	for _, option := range node.AlterOptions {
		switch altOption := option.(type) {
		case *RenameTableName:
			return TableNames{altOption.Table}
		}
	}
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *CreateView) GetToTables() TableNames {
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *AlterView) GetToTables() TableNames {
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *CreateTable) GetToTables() TableNames {
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *DropTable) GetToTables() TableNames {
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *DropView) GetToTables() TableNames {
	return nil
}

// AffectedTables returns the list table names affected by the DDLStatement.
func (node *RenameTable) AffectedTables() TableNames {
	list := make(TableNames, 0, 2*len(node.TablePairs))
	for _, pair := range node.TablePairs {
		list = append(list, pair.FromTable)
		list = append(list, pair.ToTable)
	}
	return list
}

// AffectedTables returns the list table names affected by the DDLStatement.
func (node *AlterTable) AffectedTables() TableNames {
	affectedTables := TableNames{node.Table}
	for _, option := range node.AlterOptions {
		switch altOption := option.(type) {
		case *RenameTableName:
			affectedTables = append(affectedTables, altOption.Table)
		}
	}
	return affectedTables
}

// AffectedTables implements DDLStatement.
func (node *TruncateTable) AffectedTables() TableNames {
	return TableNames{node.Table}
}

// AffectedTables implements DDLStatement.
func (node *CreateTable) AffectedTables() TableNames {
	return TableNames{node.Table}
}

// AffectedTables implements DDLStatement.
func (node *CreateView) AffectedTables() TableNames {
	return TableNames{node.ViewName}
}

// AffectedTables implements DDLStatement.
func (node *AlterView) AffectedTables() TableNames {
	return TableNames{node.ViewName}
}

// AffectedTables returns the list table names affected by the DDLStatement.
func (node *DropTable) AffectedTables() TableNames {
	return node.FromTables
}

// AffectedTables returns the list table names affected by the DDLStatement.
func (node *DropView) AffectedTables() TableNames {
	return node.FromTables
}

// SetTable implements DDLStatement.
func (node *TruncateTable) SetTable(qualifier string, name string) {
	node.Table.Qualifier = NewTableIdent(qualifier)
	node.Table.Name = NewTableIdent(name)
}

// SetTable implements DDLStatement.
func (node *AlterTable) SetTable(qualifier string, name string) {
	node.Table.Qualifier = NewTableIdent(qualifier)
	node.Table.Name = NewTableIdent(name)
}

// SetTable implements DDLStatement.
func (node *CreateTable) SetTable(qualifier string, name string) {
	node.Table.Qualifier = NewTableIdent(qualifier)
	node.Table.Name = NewTableIdent(name)
}

// SetTable implements DDLStatement.
func (node *CreateView) SetTable(qualifier string, name string) {
	node.ViewName.Qualifier = NewTableIdent(qualifier)
	node.ViewName.Name = NewTableIdent(name)
}

// SetTable implements DDLStatement.
func (node *AlterView) SetTable(qualifier string, name string) {
	node.ViewName.Qualifier = NewTableIdent(qualifier)
	node.ViewName.Name = NewTableIdent(name)
}

// SetTable implements DDLStatement.
func (node *RenameTable) SetTable(qualifier string, name string) {}

// SetTable implements DDLStatement.
func (node *DropTable) SetTable(qualifier string, name string) {}

// SetTable implements DDLStatement.
func (node *DropView) SetTable(qualifier string, name string) {}

func (*DropDatabase) iDBDDLStatement()   {}
func (*CreateDatabase) iDBDDLStatement() {}
func (*AlterDatabase) iDBDDLStatement()  {}

// IsFullyParsed implements the DBDDLStatement interface
func (node *DropDatabase) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DBDDLStatement interface
func (node *DropDatabase) SetFullyParsed(fullyParsed bool) {}

// IsFullyParsed implements the DBDDLStatement interface
func (node *CreateDatabase) IsFullyParsed() bool {
	return node.FullyParsed
}

// SetFullyParsed implements the DBDDLStatement interface
func (node *CreateDatabase) SetFullyParsed(fullyParsed bool) {
	node.FullyParsed = fullyParsed
}

// IsFullyParsed implements the DBDDLStatement interface
func (node *AlterDatabase) IsFullyParsed() bool {
	return node.FullyParsed
}

// SetFullyParsed implements the DBDDLStatement interface
func (node *AlterDatabase) SetFullyParsed(fullyParsed bool) {
	node.FullyParsed = fullyParsed
}

// GetDatabaseName implements the DBDDLStatement interface
func (node *DropDatabase) GetDatabaseName() string {
	return node.DBName.String()
}

// GetDatabaseName implements the DBDDLStatement interface
func (node *CreateDatabase) GetDatabaseName() string {
	return node.DBName.String()
}

// GetDatabaseName implements the DBDDLStatement interface
func (node *AlterDatabase) GetDatabaseName() string {
	return node.DBName.String()
}

type (

	// ShowInternal will represent all the show statement types.
	ShowInternal interface {
		isShowInternal()
		SQLNode
	}

	// ShowLegacy is of ShowInternal type, holds the legacy show ast struct.
	ShowLegacy struct {
		Extended               string
		Type                   string
		OnTable                TableName
		Table                  TableName
		ShowTablesOpt          *ShowTablesOpt
		Scope                  Scope
		ShowCollationFilterOpt Expr
	}

	// ShowCommandType represents the show statement type.
	ShowCommandType int8

	// ShowBasic is of ShowInternal type, holds Simple SHOW queries with a filter.
	ShowBasic struct {
		Command ShowCommandType
		Full    bool
		Tbl     TableName
		DbName  TableIdent
		Filter  *ShowFilter
	}

	// ShowCreate is of ShowInternal type, holds SHOW CREATE queries.
	ShowCreate struct {
		Command ShowCommandType
		Op      TableName
	}
)

func (*ShowLegacy) isShowInternal() {}
func (*ShowBasic) isShowInternal()  {}
func (*ShowCreate) isShowInternal() {}

// InsertRows represents the rows for an INSERT statement.
type InsertRows interface {
	iInsertRows()
	SQLNode
}

func (*Select) iInsertRows() {}
func (*Union) iInsertRows()  {}
func (Values) iInsertRows()  {}

// OptLike works for create table xxx like xxx
type OptLike struct {
	LikeTable TableName
}

// PartitionSpec describe partition actions (for alter statements)
type PartitionSpec struct {
	Action            PartitionSpecAction
	Names             Partitions
	Number            *Literal
	IsAll             bool
	TableName         TableName
	WithoutValidation bool
	Definitions       []*PartitionDefinition
}

// PartitionSpecAction is an enum for PartitionSpec.Action
type PartitionSpecAction int8

// PartitionDefinition describes a very minimal partition definition
type PartitionDefinition struct {
	Name     ColIdent
	Limit    Expr
	Maxvalue bool
}

// PartitionOption describes partitioning control (for create table statements)
type PartitionOption struct {
	Linear       string
	isHASH       bool
	isKEY        bool
	KeyAlgorithm string
	KeyColList   Columns
	RangeOrList  string
	ExprOrCol    *ExprOrColumns
	Expr         Expr
	Partitions   string
	SubPartition *SubPartition
	Definitions  []*PartitionDefinition
}

// ExprOrColumns describes expression and columnlist in the partition
type ExprOrColumns struct {
	Expr       Expr
	ColumnList Columns
}

// SubPartition describes subpartitions control
type SubPartition struct {
	Linear        string
	isHASH        bool
	isKEY         bool
	KeyAlgorithm  string
	KeyColList    Columns
	Expr          Expr
	SubPartitions string
}

// TableOptions specifies a list of table options
type TableOptions []*TableOption

// TableSpec describes the structure of a table from a CREATE TABLE statement
type TableSpec struct {
	Columns         []*ColumnDefinition
	Indexes         []*IndexDefinition
	Constraints     []*ConstraintDefinition
	Options         TableOptions
	PartitionOption *PartitionOption
}

// ColumnDefinition describes a column in a CREATE TABLE statement
type ColumnDefinition struct {
	Name ColIdent
	// TODO: Should this not be a reference?
	Type ColumnType
}

// ColumnType represents a sql type in a CREATE TABLE statement
// All optional fields are nil if not specified
type ColumnType struct {
	// The base type string
	Type string

	// Generic field options.
	Options *ColumnTypeOptions

	// Numeric field options
	Length   *Literal
	Unsigned bool
	Zerofill bool
	Scale    *Literal

	// Text field options
	Charset string

	// Enum values
	EnumValues []string
}

// ColumnStorage is an enum that defines the type of storage.
type ColumnStorage int

// ColumnTypeOptions are generic field options for a column type
type ColumnTypeOptions struct {
	/* We need Null to be *bool to distinguish 3 cases -
	1. When Not Null is specified (Null = false)
	2. When Null is specified (Null = true)
	3. When nothing is specified (Null = nil)
	The complexity arises from the fact that we do not know whether the column will be nullable or not if nothing is specified.
	Therefore we do not know whether the column is nullable or not in case 3.
	*/
	Null          *bool
	Autoincrement bool
	Default       Expr
	OnUpdate      Expr
	As            Expr
	Comment       *Literal
	Storage       ColumnStorage
	Collate       string
	// Reference stores a foreign key constraint for the given column
	Reference *ReferenceDefinition

	// Key specification
	KeyOpt ColumnKeyOption
}

// IndexDefinition describes an index in a CREATE TABLE statement
type IndexDefinition struct {
	Info    *IndexInfo
	Columns []*IndexColumn
	Options []*IndexOption
}

// IndexInfo describes the name and type of an index in a CREATE TABLE statement
type IndexInfo struct {
	Type           string
	Name           ColIdent
	ConstraintName ColIdent
	Primary        bool
	Spatial        bool
	Fulltext       bool
	Unique         bool
}

// VindexSpec defines a vindex for a CREATE VINDEX or DROP VINDEX statement
type VindexSpec struct {
	Name   ColIdent
	Type   ColIdent
	Params []VindexParam
}

// AutoIncSpec defines and autoincrement value for a ADD AUTO_INCREMENT statement
type AutoIncSpec struct {
	Column   ColIdent
	Sequence TableName
}

// VindexParam defines a key/value parameter for a CREATE VINDEX statement
type VindexParam struct {
	Key ColIdent
	Val string
}

// ConstraintDefinition describes a constraint in a CREATE TABLE statement
type ConstraintDefinition struct {
	Name    ColIdent
	Details ConstraintInfo
}

type (
	// ConstraintInfo details a constraint in a CREATE TABLE statement
	ConstraintInfo interface {
		SQLNode
		iConstraintInfo()
	}

	// ForeignKeyDefinition describes a foreign key in a CREATE TABLE statement
	ForeignKeyDefinition struct {
		Source              Columns
		IndexName           ColIdent
		ReferenceDefinition *ReferenceDefinition
	}

	// ReferenceDefinition describes the referenced tables and columns that the foreign key references
	ReferenceDefinition struct {
		ReferencedTable   TableName
		ReferencedColumns Columns
		OnDelete          ReferenceAction
		OnUpdate          ReferenceAction
	}

	// CheckConstraintDefinition describes a check constraint in a CREATE TABLE statement
	CheckConstraintDefinition struct {
		Expr     Expr
		Enforced bool
	}
)

// ShowFilter is show tables filter
type ShowFilter struct {
	Like   string
	Filter Expr
}

// Comments represents a list of comments.
type Comments []string

// SelectExprs represents SELECT expressions.
type SelectExprs []SelectExpr

type (
	// SelectExpr represents a SELECT expression.
	SelectExpr interface {
		iSelectExpr()
		SQLNode
	}

	// StarExpr defines a '*' or 'table.*' expression.
	StarExpr struct {
		TableName TableName
	}

	// AliasedExpr defines an aliased SELECT expression.
	AliasedExpr struct {
		Expr Expr
		As   ColIdent
	}

	// Nextval defines the NEXT VALUE expression.
	Nextval struct {
		Expr Expr
	}
)

func (*StarExpr) iSelectExpr()    {}
func (*AliasedExpr) iSelectExpr() {}
func (*Nextval) iSelectExpr()     {}

// Columns represents an insert column list.
type Columns []ColIdent

// Partitions is a type alias for Columns so we can handle printing efficiently
type Partitions Columns

// TableExprs represents a list of table expressions.
type TableExprs []TableExpr

type (
	// TableExpr represents a table expression.
	TableExpr interface {
		iTableExpr()
		SQLNode
	}

	// AliasedTableExpr represents a table expression
	// coupled with an optional alias or index hint.
	// If As is empty, no alias was used.
	AliasedTableExpr struct {
		Expr       SimpleTableExpr
		Partitions Partitions
		As         TableIdent
		Hints      *IndexHints
		Columns    Columns
	}

	// JoinTableExpr represents a TableExpr that's a JOIN operation.
	JoinTableExpr struct {
		LeftExpr  TableExpr
		Join      JoinType
		RightExpr TableExpr
		Condition *JoinCondition
	}

	// JoinType represents the type of Join for JoinTableExpr
	JoinType int8

	// ParenTableExpr represents a parenthesized list of TableExpr.
	ParenTableExpr struct {
		Exprs TableExprs
	}
)

func (*AliasedTableExpr) iTableExpr() {}
func (*ParenTableExpr) iTableExpr()   {}
func (*JoinTableExpr) iTableExpr()    {}

type (
	// SimpleTableExpr represents a simple table expression.
	SimpleTableExpr interface {
		iSimpleTableExpr()
		SQLNode
	}

	// TableName represents a table  name.
	// Qualifier, if specified, represents a database or keyspace.
	// TableName is a value struct whose fields are case sensitive.
	// This means two TableName vars can be compared for equality
	// and a TableName can also be used as key in a map.
	TableName struct {
		Name, Qualifier TableIdent
	}

	// Subquery represents a subquery used as an value expression.
	Subquery struct {
		Select SelectStatement
	}

	// DerivedTable represents a subquery used as a table expression.
	DerivedTable struct {
		Select SelectStatement
	}
)

func (TableName) iSimpleTableExpr()     {}
func (*DerivedTable) iSimpleTableExpr() {}

// TableNames is a list of TableName.
type TableNames []TableName

// JoinCondition represents the join conditions (either a ON or USING clause)
// of a JoinTableExpr.
type JoinCondition struct {
	On    Expr
	Using Columns
}

// IndexHints represents a list of index hints.
type IndexHints struct {
	Type    IndexHintsType
	Indexes []ColIdent
}

// IndexHintsType is an enum for IndexHints.Type
type IndexHintsType int8

// Where represents a WHERE or HAVING clause.
type Where struct {
	Type WhereType
	Expr Expr
}

// WhereType is an enum for Where.Type
type WhereType int8

// *********** Expressions
type (
	// Expr represents an expression.
	Expr interface {
		iExpr()
		SQLNode
	}

	// AndExpr represents an AND expression.
	AndExpr struct {
		Left, Right Expr
	}

	// OrExpr represents an OR expression.
	OrExpr struct {
		Left, Right Expr
	}

	// XorExpr represents an XOR expression.
	XorExpr struct {
		Left, Right Expr
	}

	// NotExpr represents a NOT expression.
	NotExpr struct {
		Expr Expr
	}

	// ComparisonExpr represents a two-value comparison expression.
	ComparisonExpr struct {
		Operator    ComparisonExprOperator
		Left, Right Expr
		Escape      Expr
	}

	// ComparisonExprOperator is an enum for ComparisonExpr.Operator
	ComparisonExprOperator int8

	// BetweenExpr represents a BETWEEN or a NOT BETWEEN expression.
	BetweenExpr struct {
		IsBetween bool
		Left      Expr
		From, To  Expr
	}

	// RangeCondOperator is an enum for RangeCond.Operator
	RangeCondOperator int8

	// IsExpr represents an IS ... or an IS NOT ... expression.
	IsExpr struct {
		Left  Expr
		Right IsExprOperator
	}

	// IsExprOperator is an enum for IsExpr.Operator
	IsExprOperator int8

	// ExistsExpr represents an EXISTS expression.
	ExistsExpr struct {
		Subquery *Subquery
	}

	// Literal represents a fixed value.
	Literal struct {
		Type ValType
		Val  string
	}

	// Argument represents bindvariable expression
	Argument string

	// NullVal represents a NULL value.
	NullVal struct{}

	// BoolVal is true or false.
	BoolVal bool

	// ColName represents a column name.
	ColName struct {
		// Metadata is not populated by the parser.
		// It's a placeholder for analyzers to store
		// additional data, typically info about which
		// table or column this node references.
		Metadata  interface{}
		Name      ColIdent
		Qualifier TableName
	}

	// ColTuple represents a list of column values.
	// It can be ValTuple, Subquery, ListArg.
	ColTuple interface {
		iColTuple()
		Expr
	}

	// ListArg represents a named list argument.
	ListArg string

	// ValTuple represents a tuple of actual values.
	ValTuple Exprs

	// BinaryExpr represents a binary value expression.
	BinaryExpr struct {
		Operator    BinaryExprOperator
		Left, Right Expr
	}

	// BinaryExprOperator is an enum for BinaryExpr.Operator
	BinaryExprOperator int8

	// UnaryExpr represents a unary value expression.
	UnaryExpr struct {
		Operator UnaryExprOperator
		Expr     Expr
	}

	// UnaryExprOperator is an enum for UnaryExpr.Operator
	UnaryExprOperator int8

	// IntroducerExpr represents a unary value expression.
	IntroducerExpr struct {
		CharacterSet string
		Expr         Expr
	}

	// IntervalExpr represents a date-time INTERVAL expression.
	IntervalExpr struct {
		Expr Expr
		Unit string
	}

	// TimestampFuncExpr represents the function and arguments for TIMESTAMP{ADD,DIFF} functions.
	TimestampFuncExpr struct {
		Name  string
		Expr1 Expr
		Expr2 Expr
		Unit  string
	}

	// ExtractFuncExpr represents the function and arguments for EXTRACT(YEAR FROM '2019-07-02') type functions.
	ExtractFuncExpr struct {
		IntervalTypes IntervalTypes
		Expr          Expr
	}

	// CollateExpr represents dynamic collate operator.
	CollateExpr struct {
		Expr      Expr
		Collation string
	}

	// FuncExpr represents a function call.
	FuncExpr struct {
		Qualifier TableIdent
		Name      ColIdent
		Distinct  bool
		Exprs     SelectExprs
	}

	// GroupConcatExpr represents a call to GROUP_CONCAT
	GroupConcatExpr struct {
		Distinct  bool
		Exprs     SelectExprs
		OrderBy   OrderBy
		Separator string
		Limit     *Limit
	}

	// ValuesFuncExpr represents a function call.
	ValuesFuncExpr struct {
		Name *ColName
	}

	// SubstrExpr represents a calls to
	// - SubstrExpr(expression, expression, expression)
	// - SubstrExpr(expression, expression)
	// - SubstrExpr(expression FROM expression)
	// - SubstrExpr(expression FROM expression FOR expression)
	SubstrExpr struct {
		Name Expr
		From Expr
		To   Expr
	}

	// ConvertExpr represents a call to CONVERT(expr, type)
	// or it's equivalent CAST(expr AS type). Both are rewritten to the former.
	ConvertExpr struct {
		Expr Expr
		Type *ConvertType
	}

	// ConvertUsingExpr represents a call to CONVERT(expr USING charset).
	ConvertUsingExpr struct {
		Expr Expr
		Type string
	}

	// MatchExpr represents a call to the MATCH function
	MatchExpr struct {
		Columns SelectExprs
		Expr    Expr
		Option  MatchExprOption
	}

	// MatchExprOption is an enum for MatchExpr.Option
	MatchExprOption int8

	// CaseExpr represents a CASE expression.
	CaseExpr struct {
		Expr  Expr
		Whens []*When
		Else  Expr
	}

	// Default represents a DEFAULT expression.
	Default struct {
		ColName string
	}

	// When represents a WHEN sub-expression.
	When struct {
		Cond Expr
		Val  Expr
	}

	// CurTimeFuncExpr represents the function and arguments for CURRENT DATE/TIME functions
	// supported functions are documented in the grammar
	CurTimeFuncExpr struct {
		Name ColIdent
		Fsp  Expr // fractional seconds precision, integer from 0 to 6 or an Argument
	}

	// ExtractedSubquery is a subquery that has been extracted from the original AST
	// This is a struct that the parser will never produce - it's written and read by the gen4 planner
	// CAUTION: you should only change argName and hasValuesArg through the setter methods
	ExtractedSubquery struct {
		Original     Expr // original expression that was replaced by this ExtractedSubquery
		OpCode       int  // this should really be engine.PulloutOpCode, but we cannot depend on engine :(
		Subquery     *Subquery
		OtherSide    Expr // represents the side of the comparison, this field will be nil if Original is not a comparison
		NeedsRewrite bool // tells whether we need to rewrite this subquery to Original or not

		hasValuesArg string
		argName      string
		alternative  Expr // this is what will be used to Format this struct
	}
)

// iExpr ensures that only expressions nodes can be assigned to a Expr
func (*AndExpr) iExpr()           {}
func (*OrExpr) iExpr()            {}
func (*XorExpr) iExpr()           {}
func (*NotExpr) iExpr()           {}
func (*ComparisonExpr) iExpr()    {}
func (*BetweenExpr) iExpr()       {}
func (*IsExpr) iExpr()            {}
func (*ExistsExpr) iExpr()        {}
func (*Literal) iExpr()           {}
func (Argument) iExpr()           {}
func (*NullVal) iExpr()           {}
func (BoolVal) iExpr()            {}
func (*ColName) iExpr()           {}
func (ValTuple) iExpr()           {}
func (*Subquery) iExpr()          {}
func (ListArg) iExpr()            {}
func (*BinaryExpr) iExpr()        {}
func (*UnaryExpr) iExpr()         {}
func (*IntroducerExpr) iExpr()    {}
func (*IntervalExpr) iExpr()      {}
func (*CollateExpr) iExpr()       {}
func (*FuncExpr) iExpr()          {}
func (*TimestampFuncExpr) iExpr() {}
func (*ExtractFuncExpr) iExpr()   {}
func (*CurTimeFuncExpr) iExpr()   {}
func (*CaseExpr) iExpr()          {}
func (*ValuesFuncExpr) iExpr()    {}
func (*ConvertExpr) iExpr()       {}
func (*SubstrExpr) iExpr()        {}
func (*ConvertUsingExpr) iExpr()  {}
func (*MatchExpr) iExpr()         {}
func (*GroupConcatExpr) iExpr()   {}
func (*Default) iExpr()           {}
func (*ExtractedSubquery) iExpr() {}

// Exprs represents a list of value expressions.
// It's not a valid expression because it's not parenthesized.
type Exprs []Expr

func (ValTuple) iColTuple()  {}
func (*Subquery) iColTuple() {}
func (ListArg) iColTuple()   {}

// ConvertType represents the type in call to CONVERT(expr, type)
type ConvertType struct {
	Type     string
	Length   *Literal
	Scale    *Literal
	Operator ConvertTypeOperator
	Charset  string
}

// ConvertTypeOperator is an enum for ConvertType.Operator
type ConvertTypeOperator int8

// GroupBy represents a GROUP BY clause.
type GroupBy []Expr

// OrderBy represents an ORDER By clause.
type OrderBy []*Order

// Order represents an ordering expression.
type Order struct {
	Expr      Expr
	Direction OrderDirection
}

// OrderDirection is an enum for the direction in which to order - asc or desc.
type OrderDirection int8

// Limit represents a LIMIT clause.
type Limit struct {
	Offset, Rowcount Expr
}

// Values represents a VALUES clause.
type Values []ValTuple

// UpdateExprs represents a list of update expressions.
type UpdateExprs []*UpdateExpr

// UpdateExpr represents an update expression.
type UpdateExpr struct {
	Name *ColName
	Expr Expr
}

// SetExprs represents a list of set expressions.
type SetExprs []*SetExpr

// SetExpr represents a set expression.
type SetExpr struct {
	Scope Scope
	Name  ColIdent
	Expr  Expr
}

// OnDup represents an ON DUPLICATE KEY clause.
type OnDup UpdateExprs

// ColIdent is a case insensitive SQL identifier. It will be escaped with
// backquotes if necessary.
type ColIdent struct {
	// This artifact prevents this struct from being compared
	// with itself. It consumes no space as long as it's not the
	// last field in the struct.
	_            [0]struct{ _ []byte }
	val, lowered string
	at           AtCount
}

// TableIdent is a case sensitive SQL identifier. It will be escaped with
// backquotes if necessary.
type TableIdent struct {
	v string
}

// AtCount return the '@' count present in ColIdent Name
func (node ColIdent) AtCount() AtCount {
	return node.at
}

func (IsolationLevel) iChar() {}
func (AccessMode) iChar()     {}
